﻿using System;
using System.ComponentModel;
using RaytracerLib.MathLib;

namespace Raytracer.PropertyGridDecorators
{
    public class Matrix4Properties
    {
        public readonly Action<Matrix4> Setter;
        public readonly Func<Matrix4> Getter;

        public Matrix4Properties(Func<Matrix4> a_getter, Action<Matrix4> a_setter)
        {
            Getter = a_getter;
            Setter = a_setter;
        }

        public double[] ToArray()
        {
            return new double[]
            {
                Getter().M11, Getter().M12, Getter().M13, Getter().M14,
                Getter().M21, Getter().M22, Getter().M23, Getter().M24,
                Getter().M31, Getter().M32, Getter().M33, Getter().M34,
                Getter().M41, Getter().M42, Getter().M43, Getter().M44
            };
        }

        public double this[int a_index]
        {
            get
            {
                return ToArray()[a_index];
            }
            set
            {
                var ar = ToArray();
                ar[a_index] = value;
                Setter(new Matrix4(ar));
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M11
        {
            get
            {
                return this[0];
            }
            set
            {
                this[0] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M12
        {
            get
            {
                return this[1];
            }
            set
            {
                this[1] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M13
        {
            get
            {
                return this[2];
            }
            set
            {
                this[2] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M14
        {
            get
            {
                return this[3];
            }
            set
            {
                this[3] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M21
        {
            get
            {
                return this[4];
            }
            set
            {
                this[4] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M22
        {
            get
            {
                return this[5];
            }
            set
            {
                this[5] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M23
        {
            get
            {
                return this[6];
            }
            set
            {
                this[6] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M24
        {
            get
            {
                return this[7];
            }
            set
            {
                this[7] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M31
        {
            get
            {
                return this[8];
            }
            set
            {
                this[8] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M32
        {
            get
            {
                return this[9];
            }
            set
            {
                this[9] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M33
        {
            get
            {
                return this[10];
            }
            set
            {
                this[10] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M34
        {
            get
            {
                return this[11];
            }
            set
            {
                this[11] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M41
        {
            get
            {
                return this[12];
            }
            set
            {
                this[12] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M42
        {
            get
            {
                return this[13];
            }
            set
            {
                this[13] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M43
        {
            get
            {
                return this[14];
            }
            set
            {
                this[14] = value;
            }
        }

        [TypeConverter(typeof(DoubleConverter))]
        public double M44
        {
            get
            {
                return this[15];
            }
            set
            {
                this[15] = value;
            }
        }

        [TypeConverter(typeof(Vector3Converter))]
        public Vector3Properties Col1
        {
            get
            {
                return new Vector3Properties(
                    () => Getter().Col1,
                    (v) => Setter(Getter().SetCol1(v)));
            }
            set
            {
                Setter(Getter().SetCol1(value.ToVector3()));
            }
        }

        [TypeConverter(typeof(Vector3Converter))]
        public Vector3Properties Col2
        {
            get
            {
                return new Vector3Properties(
                    () => Getter().Col2,
                    (v) => Setter(Getter().SetCol2(v)));
            }
            set
            {
                Setter(Getter().SetCol2(value.ToVector3()));
            }
        }

        [TypeConverter(typeof(Vector3Converter))]
        public Vector3Properties Col3
        {
            get
            {
                return new Vector3Properties(
                    () => Getter().Col3,
                    (v) => Setter(Getter().SetCol3(v)));
            }
            set
            {
                Setter(Getter().SetCol3(value.ToVector3()));
            }
        }

        [TypeConverter(typeof(Vector3Converter))]
        public Vector3Properties Col4
        {
            get
            {
                return new Vector3Properties(
                    () => Getter().Col4,
                    (v) => Setter(Getter().SetCol4(v)));
            }
            set
            {
                Setter(Getter().SetCol4(value.ToVector3()));
            }
        }

        public Matrix4 ToMatrix4()
        {
            return new Matrix4(ToArray());
        }
    }
}